<template>
	<el-row class="model" type="flex" justify="center" align="middle">
		<el-col :span="24">
			<el-row type="flex" justify="center" align="middle">
				<el-card :body-style="{ padding: '0px' }" id="loading">
					<div class="card-top">
						<div @click="dealCanvas">
							<span></span>
						</div>
					</div>

					<div class="card-body" @click="runTask" :style="cardStyle">
						<img alt="测试图片" ref="img" :src="imgsrc" v-show="flag != 2" />
						<canvas ref="canvas" v-show="flag == 2"></canvas>
					</div>

					<div class="card-bottom">
						<div @click="openBox">
							<span></span>
						</div>
					</div>
				</el-card>
			</el-row>
		</el-col>
	</el-row>
</template>

<script setup lang="ts">
import { ref, defineProps, nextTick, defineEmit } from "vue";
import { ElLoading, Msgbox, Message } from "element3";

const flag = ref(0);
const imgsrc = ref(window.$assets.pixDemo);

const emit = defineEmit(["change-img"]);

const img = ref(null);
const canvas = ref(null);

const props = defineProps({
	cardStyle: {
		type: Object,
		required: true,
	},
});

function runBodyPix(callback?: () => any, errorHandler?: (e: Error) => any) {
	(async function loadAndPredict() {
		const net = await window.bodyPix.load();

		const segmentation = await net
			.segmentMultiPersonParts(img.value)

			.catch((e: Error) => {
				if (errorHandler) {
					errorHandler(e);
				}
			});

		const opacity = 1;
		const maskBlurAmount = 0;
		const flipHorizontal = false;
		const coloredPartImage = bodyPix.toColoredPartMask(segmentation);

		if (callback) {
			callback();
		}

		window.bodyPix.drawMask(
			canvas.value,
			img.value,
			coloredPartImage,
			opacity,
			maskBlurAmount,
			flipHorizontal
		);
	})();
}

function runTask() {
	flag.value = 1;
	const loading = ElLoading.service({
		text: "处理中",
		target: ".card-body",
		spinner: "el-icon-loading",
		background: "rgba(0, 0, 0, 0.7)",
	});

	nextTick(() =>
		runBodyPix(
			() => {
				Message({
					type: "success",
					message: "Bodypix 运行成功",
				});
				loading.close();
				flag.value = 2;
			},
			() => {
				Message.error("Bodypix 运行失败");
				loading.close();
				flag.value = 0;
			}
		)
	);
}

function openBox() {
	flag.value = 0;
	Msgbox.prompt("更改图像地址", " ", {
		confirmButtonText: "确定",
		showCancelButton: false,
		inputValue: imgsrc.value,
	})
		.then(({ value }) => {
			if (value === null || String(value).length === 0) {
				imgsrc.value = window.$assets.pixDemo;
			} else {
				imgsrc.value = String(value);
			}
			emit("change-img", imgsrc.value);
		})
		.catch(() => {
			Message({
				type: "info",
				message: "已恢复默认示例图片",
			});
			imgsrc.value = window.$assets.pixDemo;
		});
}

function dealCanvas() {
	const width = canvas.value.width;
	const height = canvas.value.height;
	const ctx = canvas.value.getContext("2d");
	const imgData = ctx.getImageData(0, 0, width, height);

	function inTarget(pixel: [number, number, number]) {
		const r = pixel[0];
		const g = pixel[1];
		const b = pixel[2];

		return (
			window.$assets.suitColor.r[0] <= r &&
			r <= window.$assets.suitColor.r[1] &&
			window.$assets.suitColor.g[0] <= g &&
			g <= window.$assets.suitColor.g[1] &&
			window.$assets.suitColor.b[0] <= b &&
			b <= window.$assets.suitColor.b[1]
		);
	}

	let pixelList = [];

	for (let i = 0; i < imgData.data.length; i += 4) {
		const pixel = [
			imgData.data[i],
			imgData.data[i + 1],
			imgData.data[i + 2],
			imgData.data[i + 3],
		];
		const x = (i / 4) % width;
		const y = [(i - x) / width] / 4;
		pixelList.push({ x, y, pixel });
	}

	const targetList = pixelList.filter((v) => inTarget(v.pixel));

	ctx.drawImage(img.value, 0, 0);
	for (let { x, y } of targetList) {
		const imgData = ctx.createImageData(1, 1);
		for (let i = 0; i < imgData.data.length; i += 4) {
			imgData.data[i + 0] = 255;
			imgData.data[i + 1] = 255;
			imgData.data[i + 2] = 255;
			imgData.data[i + 3] = 0;
		}

		console.log(`绘制点 (${x - 12}${y - 8})`);
		ctx.putImageData(imgData, x, y);
	}

	console.log("重绘完成");
	console.log(pixelList);
	console.log(targetList);
}
</script>

<style scoped lang="less">
.model {
	.el-card {
		display: flex;
		justify-content: center;
		border-radius: 35px;
		cursor: pointer;
		box-shadow: darkgrey 10px 10px 30px 5px;

		div.card-body {
			width: 100%;
			padding: 0;
			margin: 0;
			img {
				height: 100%;
				padding: 0;
				margin: 0;
			}
		}

		div.card-top {
			width: 100%;
			height: 55px;
			background-color: rgba(0, 0, 0, 0.85);
			display: flex;
			justify-content: center;
			align-items: center;
			div {
				width: 23px;
				height: 23px;
				display: flex;
				justify-content: center;
				align-items: center;
				border-radius: 50%;
				background-color: white;
				span {
					width: 10px;
					height: 10px;
					border-radius: 50%;
					background-color: rgba(0, 0, 0, 0.85);
				}
			}
		}

		div.card-bottom {
			width: 100%;
			height: 85px;
			background-color: rgba(0, 0, 0, 0.85);
			display: flex;
			justify-content: center;
			align-items: center;
			transform: translateY(-4px);
			div {
				width: 50px;
				height: 50px;
				display: flex;
				justify-content: center;
				align-items: center;
				border-radius: 50%;
				background-color: lightgray;
				span {
					width: 30px;
					height: 30px;
					border-radius: 50%;
					background-color: white;
				}
			}
		}
	}
}
</style>
